﻿#ifndef QLIB_HEADER_KEYPOINT
#define QLIB_HEADER_KEYPOINT

#include "qlib/core/array.h"
#include "qlib/core/object.h"
#include "qlib/core/vec2.h"
#include "qlib/layout/property.h"
#include "qlib/layout/repetition.h"

#include "qlib/geo/label.h"
#include "qlib/geo/polygon.h"

#include <algorithm>
#include <cfloat>
#include <cstdint>
#include <memory>
#include <vector>

#include "qlib/geo/element.h"

namespace qlib {
enum struct GeoPartType;
class KeyPoint;
using KeyPointPtrArray = std::vector<std::shared_ptr<KeyPoint>>;
using KeyPointPtrArrayMap = std::unordered_map<Tag, KeyPointPtrArray, Tag::Hash>;
// 0: 中心
using KeyPointParts = std::tuple<Vec2d>;

/// @brief 文本对象
class QLIB_API KeyPoint : public CellElementBase {
 public:
  KeyPoint();
  KeyPoint(std::string _text, Vec2d _origin, double _rotation = 0.0, double _magnification = 1.0, bool _x_reflection = false, uint32_t _layer = 0,
           uint32_t _datatype = 0);

  KeyPoint(const KeyPoint& oth);
  KeyPoint& operator=(const KeyPoint& other);

  using s_ptr = std::shared_ptr<KeyPoint>;
  template <typename... Args>
  static s_ptr create(Args... args) {
    return std::make_shared<KeyPoint>(args...);
  }
  // template <>
  static s_ptr create() {
    return std::make_shared<KeyPoint>();
  }
  static s_ptr create(const KeyPoint& value) { return std::make_shared<KeyPoint>(value); }

  /**
   * @brief 拷贝标签
   * @details 标签对象不包含引用对象，拷贝等价于赋值。
   * @return s_ptr 拷贝结果
   */
  virtual s_ptr copy() const;
  virtual void copy(qlib::Label::s_ptr label);

  /**
   * @brief 应用重复对象创建新标签
   * @details 应用后重复对象会重置。返回的标签中不包含原位置标签。
   * @param[out] result 新标签数组
   */
  void apply_repetition(KeyPointPtrArray& result);

  /**
   * @brief 获取此对象的包围盒
   * @details 根据标签位置和重复对象获取的极值数组，确定包围盒。若不重复，则返回[origin,origin]。
   * @return Vec2dArray 元素0为包围盒左下角，元素1为右上角
   */
  Vec2dArray bounding_box() const;
  Vec2dArray bounding_box_points() { return box_to_points(bounding_box()); };

  /**
   * @brief 变换标签
   * 
   * @param[in] magnification 缩放倍率
   * @param[in] x_reflection  是否沿x轴镜像
   * @param[in] rotation      旋转角度
   * @param[in] origin        变换原点
   */
  void transform(double magnification, bool x_reflection, double rotation, const Vec2d origin);
  void rotate(double angle, Vec2d center);
  void translate(double dx, double dy);
  void mirror(qlib::Vec2d p0, qlib::Vec2d p1);
  std::vector<Polygon::s_ptr> to_polygons() const;
  Vec2dArray get_texts();

  KeyPointParts get_parts();
  Vec2dArray query_parts(GeoPartType type, uint32_t id);

  double getRotation();
  void setRotation(double rotation);

  // 渲染
  Vec2dArray render_aabb();
  std::vector<Vec2dArray> render_poly();
  Vec2dArray render_absorp();

  void savePropertiesGDS();
  void loadPropertiesGDS();

  void saveToProper();
  void readProper();

 public:
  static std::string fontPath;
  static float fontSizeBase;

  bool haveLabel = true;

  double fontSize = 1.0;

  std::string text;          ///< 文本字符串
  Vec2d origin{0.0, 0.0};    ///< 标签的位置
  Anchor anchor{Anchor::O};  ///< 原点所在的方向

  double rotation{0.0};       ///< 旋转角度(弧度)
  double magnification{1.0};  ///< 放大率-比例因子
  bool x_reflection{false};   ///< 若为KeyPointrue，则标签在旋转前，将在水平轴上反射

  uint32_t layer;            ///< 标签的图层
  uint32_t datatype;         ///< 标签的类型
  PropertyArray properties;  ///< 属性对象
  Repetition repetition;     ///< 重复对象

  mutable Vec2d offset;
  mutable Vec2d textSize;

  mutable Vec2dArray box;

  bool is_display_id;
  bool is_display_name;
  bool is_display_type;

  Vec2dArray lines;  // 渲染缓存

  void* owner;
  uint64_t reference_number;  ///< 引用编号，读写oas文件时使用
};

}  // namespace qlib

#endif